package com.mjh.config;

import com.mjh.config.filter.TokenFilter;
import com.mjh.config.handler.AppAccessDeniedHandler;
import com.mjh.config.handler.AppAuthenticationFailureHandler;
import com.mjh.config.handler.AppAuthenticationSuccessHandler;
import com.mjh.config.handler.AppLogoutSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.List;

/**
 * Security配置类
 */
@Configuration
public class SecurityConfig {
    /**
     * 配置Security过滤器链
     * @param httpSecurity
     * @return
     * @throws Exception
     */
    @Autowired
    private AppAuthenticationSuccessHandler appAuthenticationSuccessHandler;
    @Autowired
    private AppAuthenticationFailureHandler appAuthenticationFailureHandler;
    @Autowired
    private AppLogoutSuccessHandler appLogoutSuccessHandler;
    @Autowired
    private AppAccessDeniedHandler appAccessDeniedHandler;
    @Autowired
    private TokenFilter tokenFilter;
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                // 表单验证登陆项
                .formLogin((formLogin)->{
                    formLogin
                            .usernameParameter("loginAct")
                            .passwordParameter("loginPwd")
                            .loginProcessingUrl("/api/login")//登陆请求地址
                            .successHandler(appAuthenticationSuccessHandler)//登陆成功处理
                            .failureHandler(appAuthenticationFailureHandler);//登陆失败处理
                })
                .authorizeHttpRequests((authorizeHttpRequests)->{
                    authorizeHttpRequests
                            .anyRequest().authenticated();
                })
                //关闭跨站请求伪造
                .csrf(AbstractHttpConfigurer::disable)
                .cors((cors) -> {
                    cors.configurationSource(corsConfigurationSource()); // 指定CORS配置源
                })
                    //关闭session使用策略
                .sessionManagement((sessionManagement)->{
                    sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
                })
                //登出配置
                .logout((logout)->{
                    logout
                            .logoutUrl("/api/logout")
                            .logoutSuccessHandler(appLogoutSuccessHandler);//登出成功处理
                })
                .exceptionHandling((exceptionHandling)->{
                    exceptionHandling
                            .accessDeniedHandler(appAccessDeniedHandler);//访问拒绝处理权限不够
                })
                // 处理token转换过滤器
                .addFilterAfter(tokenFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
    }
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(List.of("*")); // 允许所有来源
        configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")); // 允许的方法
        configuration.setAllowedHeaders(List.of("*")); // 允许的头信息
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        /*
         * source.registerCorsConfiguration()方法用于将特定的 CORS 配置应用到指定的 URL 路径模式。
         * 这个方法允许你为不同的 URL 路径设置不同的 CORS 策略，从而实现更细粒度的控制
         * */
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

}
